﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Data.Objects;
using SuperJ.CMS.Models;

namespace SuperJ.CMS.Repositories
{
    public class CMSRepository<T> : SuperJ.CMS.Interfaces.Repositories.ICMSRepository<T> where T : class
    {
        private IObjectSet<T> _objectSet;
        private CMSDBEntities context = new SuperJ.CMS.Models.CMSDBEntities();
        private System.Data.Entity.DbContext _context
        {
            get;
            set;
        }

        public CMSRepository()
        //: this(new CMSEntities())
        {
            //CMSDBEntities context = 
            _objectSet = context.CreateObjectSet<T>();
        }

        //public CMSRepository(DbContext context)
        //{
        //    if (context == null)
        //    {
        //        throw new ArgumentNullException("context");
        //    }
        //    this._context = context;
        //}

        //public CMSRepository(ObjectContext context)
        //{
        //    if (context == null)
        //    {
        //        throw new ArgumentNullException("context");
        //    }
        //    this._context = new DbContext(context, true);
        //}

        public IQueryable<T> Fetch()
        {
            return _objectSet.AsQueryable<T>();
        }
        public IQueryable<T> Fetch<TKey>(Expression<Func<T,bool>> filter,int pageIndex,int pageSize,Expression<Func<T,TKey>> sortKeySelector,bool isAsc=true)
        {
            if (isAsc)
                return _objectSet
                    .Where(filter)
                    .OrderBy(sortKeySelector)
                    .Skip(pageSize * (pageIndex - 1))
                    .Take(pageSize).AsQueryable();
            else
                return _objectSet
                    .Where(filter)
                    .OrderByDescending(sortKeySelector)
                    .Skip(pageSize * (pageIndex - 1))
                    .Take(pageSize).AsQueryable();
        }
        public IEnumerable<T> GetAll()
        {
            return Fetch().AsEnumerable<T>();
        }
        public IQueryable<T> Where(Expression<Func<T, bool>> exp)
        {
            return Fetch().Where<T>(exp);
        }
        public IEnumerable<T> Find(Func<T, bool> predicate)
        {
            return _objectSet.Where<T>(predicate);
        }
        public IEnumerable<T> Where(Func<T, bool> predicate)
        {

            return _objectSet.Where<T>(predicate);
        }

        public T Single(Func<T, bool> predicate)
        {
            return _objectSet.Single<T>(predicate);
        }

        public T SingleOrDefault(Func<T, bool> predicate)
        {
            return _objectSet.SingleOrDefault<T>(predicate);
        }

        public T First(Func<T, bool> predicate)
        {

            return _objectSet.First<T>(predicate);
        }

        public void Delete(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            _objectSet.DeleteObject(entity);
        }

        public void Delete(Func<T, bool> predicate)
        {
            IEnumerable<T> records = from x in _objectSet.Where<T>(predicate) select x;

            foreach (T record in records)
            {
                _objectSet.DeleteObject(record);
            }
        }
        public int Count()
        {
            return _objectSet.Count();
        }
        public void Create(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            _objectSet.AddObject(entity);
            this.SaveChanges();
        }

        public void Attach(T entity)
        {
            _objectSet.Attach(entity);
        }
        //public static IQueryable<T> PageQuery<T, TOrderBy,a,b,c>(Func<T, TResult> predicate, dynamic d, int page, int pageSize)
        //{
        //    //vipSignInDB.Admin.OrderByDescending(p => p.CreateTime).Skip((page - 1) * 10).Take(10).ToList();
        //    //OrderByDescending<T, bool>(predicate).
        //    return _objectSet.OrderByDescending<T>(predicate).Skip<T>((page - 1) * pageSize).Take<T>(pageSize);
        //}
        public void SaveChanges()
        {
            context.SaveChanges();
        }
        public IQueryable<T> PageQuery(string propertyName, int page, int pageSize)
        {
            return OrderBy(Fetch(), propertyName, false).Skip<T>((page - 1) * pageSize).Take<T>(pageSize);
        }
        public IQueryable<T> PageQuery(string propertyName, bool desc, int page, int pageSize)
        {
            return OrderBy(Fetch(), propertyName, desc).Skip<T>((page - 1) * pageSize).Take<T>(pageSize);
        }
        public IQueryable<T> OrderBy(string propertyName)
        {
            return OrderBy(Fetch(), propertyName, false);
        }

        public IQueryable<T> OrderBy(string propertyName, bool desc)
        {
            IQueryable<T> iq = Fetch();
            return OrderBy(iq, propertyName, desc);
        }

        private Dictionary<string, LambdaExpression> cache = new Dictionary<string, LambdaExpression>();
        private IQueryable<T> OrderBy(IQueryable<T> queryable, string propertyName, bool desc)
        {
            dynamic keySelector = GetLambdaExpression(propertyName);
            return desc ? Queryable.OrderByDescending(propertyName, keySelector) : Queryable.OrderBy(queryable, keySelector);
        }
        private LambdaExpression GetLambdaExpression(string propertyName)
        {
            if (cache.ContainsKey(propertyName)) return cache[propertyName];
            var param = Expression.Parameter(typeof(T));
            var body = Expression.Property(param, propertyName);
            var keySelector = Expression.Lambda(body, param);
            cache[propertyName] = keySelector;
            return keySelector;
        }
    }
}
